#include "uti_timer.h"
#include <atltime.h>


CTimer::CTimer(unsigned int interval,   // interval in ms
	unsigned int duetime,// true to call first event immediately
	bool once)       // true to call timed event only once
{
	m_hTimer = NULL;
	m_hTimerStop = NULL;

	m_hTimerQueue = NULL;
	m_hTimerQueuestop = NULL;


	if (false == Start(interval, duetime, once))
	{
		printf("[CTimer] Start Failed\n");
	}

}

CTimer::~CTimer()
{
	if (false == Stop())
	{
		printf("[CTimer] Stop Failed\n");
	}
}


bool CTimer::Start(unsigned int interval,   // interval in ms
	unsigned int duetime,// true to call first event immediately
	bool once)       // true to call timed event only once
{
	if( m_hTimer || m_hTimerStop || m_hTimerQueue || m_hTimerQueuestop)
	{
		printf("[Start] Not NULL\n");
		return false;
	}

	m_hTimerQueuestop = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (NULL == m_hTimerQueuestop)
	{
		printf("[Start] m_hTimerQueuestop failed (%d)\n", GetLastError());
		return false;
	}

	// Create the timer queue.
	m_hTimerQueue = CreateTimerQueue();
	if (NULL == m_hTimerQueue)
	{
		printf("[Start] m_hTimerQueue failed (%d)\n", GetLastError());
		return false;
	}

	m_hTimerStop = CreateEvent(NULL, FALSE, FALSE, NULL);
	if (NULL == m_hTimerStop)
	{
		printf("[Start] m_hTimerStop failed (%d)\n", GetLastError());
		return false;
	}


	BOOL success = CreateTimerQueueTimer( &m_hTimer,
		NULL,
		CTimerRoutine::TimerRoutine,
		NULL,
		duetime,
		once ? 0 : interval,
		//WT_EXECUTEDEFAULT);
		WT_EXECUTEINTIMERTHREAD);

	return( success != 0 );
}

bool CTimer::Stop()
{
	if (m_hTimer && m_hTimerStop && m_hTimerQueue && m_hTimerQueuestop)
	{
		//CTimeCounter tc;
		//tc.Start();
		if (false == DeleteTimerQueueTimer(m_hTimerQueue, m_hTimer, m_hTimerStop) && ERROR_IO_PENDING !=  GetLastError())
		{
			printf("[Stop] DeleteTimerQueueTimer failed (%d)\n", GetLastError());
			return false;
		}
		//printf("DeleteTimerQueueTimer Elapse %0.2f ms\n", tc.Elapse());

		//tc.Start();
		if (WAIT_OBJECT_0 != WaitForSingleObject(m_hTimerStop, INFINITE))
		{
			printf("[Stop] WaitForSingleObject m_hTimerStop failed (%d)\n", GetLastError());
			return false;
		}
		CloseHandle(m_hTimerStop);
		m_hTimerStop = NULL;
		//printf("WaitForSingleObject Elapse %0.2f ms\n", tc.Elapse());

		//tc.Start();
		if (false == DeleteTimerQueueEx(m_hTimerQueue, m_hTimerQueuestop))
		{
			printf("[Stop] DeleteTimerQueueEx failed (%d)\n", GetLastError());
			return false;
		}
		//printf("DeleteTimerQueueEx Elapse %0.2f ms\n", tc.Elapse());
		
		//tc.Start();
		if (WAIT_OBJECT_0 != WaitForSingleObject(m_hTimerQueuestop, INFINITE))
		{
			printf("[Stop] WaitForSingleObject m_hTimerQueuestop failed (%d)\n", GetLastError());
			return false;
		}
		CloseHandle(m_hTimerQueuestop);
		m_hTimerQueuestop = NULL;
		//printf("WaitForSingleObject Elapse %0.2f ms\n", tc.Elapse());



	} 
	else
	{
		printf("[Stop]  m_hTimer || m_hTimerStop || m_hTimerQueue || m_hTimerQueuestop NULL\n");
		return false;
	}

	return true;
}




//#################################################################################################################
//#################################################################################################################
//#################################################################################################################


//#if (0 == RUN_STATE || 1 == RUN_STATE)
//const unsigned int DB_FIRETIME_0_STARTHOUR = 0;	
//const unsigned int DB_FIRETIME_0_STARTMIN = 0;	
//const unsigned int DB_FIRETIME_0_STARTSEC = 0;	
//const unsigned int DB_FIRETIME_0_ENDHOUR = 23;	
//const unsigned int DB_FIRETIME_0_ENDMIN = 59;	
//const unsigned int DB_FIRETIME_0_ENDSEC = 59;	
//const unsigned int DB_FIRETIME_1_STARTHOUR = 0;	
//const unsigned int DB_FIRETIME_1_STARTMIN = 0;	
//const unsigned int DB_FIRETIME_1_STARTSEC = 0;	
//const unsigned int DB_FIRETIME_1_ENDHOUR = 23;	
//const unsigned int DB_FIRETIME_1_ENDMIN = 59;	
//const unsigned int DB_FIRETIME_1_ENDSEC = 59;
//
//const unsigned int APP_FIRETIME_0_STARTHOUR = 0;	
//const unsigned int APP_FIRETIME_0_STARTMIN = 0;	
//const unsigned int APP_FIRETIME_0_STARTSEC = 0;	
//const unsigned int APP_FIRETIME_0_ENDHOUR = 23;	
//const unsigned int APP_FIRETIME_0_ENDMIN = 59;	
//const unsigned int APP_FIRETIME_0_ENDSEC = 59;
//
//#else
//const unsigned int DB_FIRETIME_0_STARTHOUR = 11;	
//const unsigned int DB_FIRETIME_0_STARTMIN = 45;	
//const unsigned int DB_FIRETIME_0_STARTSEC = 0;	
//const unsigned int DB_FIRETIME_0_ENDHOUR = 12;	
//const unsigned int DB_FIRETIME_0_ENDMIN = 44;	
//const unsigned int DB_FIRETIME_0_ENDSEC = 59;	
//const unsigned int DB_FIRETIME_1_STARTHOUR = 15;	
//const unsigned int DB_FIRETIME_1_STARTMIN = 45;	
//const unsigned int DB_FIRETIME_1_STARTSEC = 0;	
//const unsigned int DB_FIRETIME_1_ENDHOUR = 16;	
//const unsigned int DB_FIRETIME_1_ENDMIN = 44;	
//const unsigned int DB_FIRETIME_1_ENDSEC = 59;	
//
//const unsigned int APP_FIRETIME_0_STARTHOUR = 7;	
//const unsigned int APP_FIRETIME_0_STARTMIN = 0;	
//const unsigned int APP_FIRETIME_0_STARTSEC = 0;	
//const unsigned int APP_FIRETIME_0_ENDHOUR = 7;	
//const unsigned int APP_FIRETIME_0_ENDMIN = 59;	
//const unsigned int APP_FIRETIME_0_ENDSEC = 59;
//#endif




CTimerRoutine::CTimerRoutine()
{
	
	/********************DB Timer****************************************************/
	FireCondition fc_db[2];

	GetLocalTime(&fc_db[0].starttm);
	GetLocalTime(&fc_db[0].endtm);
	GetLocalTime(&fc_db[1].starttm);
	GetLocalTime(&fc_db[1].endtm);

	fc_db[0].type = TimerFire_namespace::dbfiretimer;		
	fc_db[0].starttm.wHour = DB_FIRETIME_0_STARTHOUR;
	fc_db[0].starttm.wMinute = DB_FIRETIME_0_STARTMIN;
	fc_db[0].starttm.wSecond = DB_FIRETIME_0_STARTSEC;
	fc_db[0].endtm.wHour = DB_FIRETIME_0_ENDHOUR;
	fc_db[0].endtm.wMinute = DB_FIRETIME_0_ENDMIN;
	fc_db[0].endtm.wSecond = DB_FIRETIME_0_ENDSEC;
	
	fc_db[1].type = TimerFire_namespace::dbfiretimer;
	fc_db[1].starttm.wHour = DB_FIRETIME_1_STARTHOUR;
	fc_db[1].starttm.wMinute = DB_FIRETIME_1_STARTMIN;
	fc_db[1].starttm.wSecond = DB_FIRETIME_1_STARTSEC;
	fc_db[1].endtm.wHour = DB_FIRETIME_1_ENDHOUR;
	fc_db[1].endtm.wMinute = DB_FIRETIME_1_ENDMIN;
	fc_db[1].endtm.wSecond = DB_FIRETIME_1_ENDSEC;
	

	m_vfirecd.push_back(fc_db[0]);
	m_vfirecd.push_back(fc_db[1]);
	/************************************************************************/


	/********************Inst Timer****************************************************/
	FireCondition fc_inst;

	GetLocalTime(&fc_inst.starttm);
	GetLocalTime(&fc_inst.endtm);


	fc_inst.type = TimerFire_namespace::instfiretimer;		
	fc_inst.starttm.wHour = INST_FIRETIME_0_STARTHOUR;
	fc_inst.starttm.wMinute = INST_FIRETIME_0_STARTMIN;
	fc_inst.starttm.wSecond = INST_FIRETIME_0_STARTSEC;
	fc_inst.endtm.wHour = INST_FIRETIME_0_ENDHOUR;
	fc_inst.endtm.wMinute = INST_FIRETIME_0_ENDMIN;
	fc_inst.endtm.wSecond = INST_FIRETIME_0_ENDSEC;


	m_vfirecd.push_back(fc_inst);

	/************************************************************************/



	/********************APP Timer****************************************************/
	FireCondition fc_app;

	GetLocalTime(&fc_app.starttm);
	GetLocalTime(&fc_app.endtm);


	fc_app.type = TimerFire_namespace::appfiretimer;		
	fc_app.starttm.wHour = APP_FIRETIME_0_STARTHOUR;
	fc_app.starttm.wMinute = APP_FIRETIME_0_STARTMIN;
	fc_app.starttm.wSecond = APP_FIRETIME_0_STARTSEC;
	fc_app.endtm.wHour = APP_FIRETIME_0_ENDHOUR;
	fc_app.endtm.wMinute = APP_FIRETIME_0_ENDMIN;
	fc_app.endtm.wSecond = APP_FIRETIME_0_ENDSEC;


	m_vfirecd.push_back(fc_app);

	/************************************************************************/

}

CTimerRoutine::~CTimerRoutine(){}
//

bool CTimerRoutine::TimerFire(TimerFire_namespace::TimerFireType type)
{


	unsigned int size = m_vfirecd.size();

	for (unsigned int i = 0; i < size; i++)
	{
		//only call once one day, judge from date
		if (type == m_vfirecd[i].type && false == m_vfirecd[i].TodayFired())
		{
			SYSTEMTIME curtime;
			GetLocalTime(&curtime);

			//for across day, convert into the same day
			SetFireConditionData(curtime, m_vfirecd[i].starttm);
			SetFireConditionData(curtime, m_vfirecd[i].endtm);
			
			CTime cur_ctime(curtime);
			CTime start_ctime(m_vfirecd[i].starttm);
			CTime end_ctime(m_vfirecd[i].endtm);
			CTimeSpan startspan = cur_ctime - start_ctime;
			CTimeSpan endspan = end_ctime - cur_ctime;


			if (startspan.GetTotalSeconds() >= 0 && endspan.GetTotalSeconds() >= 0)
			{

				SetFireConditionData(curtime, m_vfirecd[i].firedata);

				return true;
			}
		}

	}


	return false;





}



void CTimerRoutine::SetFireConditionData(SYSTEMTIME& sourcetm, SYSTEMTIME& desttm)
{
	desttm.wYear = sourcetm.wYear;
	desttm.wMonth = sourcetm.wMonth;
	desttm.wDay = sourcetm.wDay;
	//desttm.wDayOfWeek = sourcetm.wDayOfWeek;
	//desttm.wHour = sourcetm.wHour;
	//desttm.wMinute = sourcetm.wMinute;
	//desttm.wSecond = sourcetm.wSecond;
	desttm.wMilliseconds = sourcetm.wMilliseconds;
	
}



CTimerAndCTimerRoutine::CTimerAndCTimerRoutine(unsigned int interval,   // interval in ms
	unsigned int duetime,// true to call first event immediately
	bool once)       // true to call timed event only once
{
	m_pctimer = new CTimer(interval, duetime, once);
	if (NULL == m_pctimer)
	{
		printf("[CTimerAndCTimerRoutine] m_pctimer NULL\n");
	}

	m_pctimer_routine = new CTimerRoutine();
	if (NULL == m_pctimer_routine)
	{
		printf("[CTimerAndCTimerRoutine] m_pctimer_routine NULL\n");
	}
}

CTimerAndCTimerRoutine::~CTimerAndCTimerRoutine()
{
	if (m_pctimer)
	{
		delete m_pctimer;
		m_pctimer = NULL;
	}


	if (m_pctimer_routine)
	{
		delete m_pctimer_routine;
		m_pctimer_routine = NULL;
	}


}

bool CTimerAndCTimerRoutine::TimerFire(TimerFire_namespace::TimerFireType type)
{
	if (m_pctimer_routine)
	{
		return m_pctimer_routine->TimerFire(type);
	} 

	return false;
}
//
//void CTimerAndCTimerRoutine::ActiveTimer()
//{
//	m_pctimer_routine->ActiveTimer();
//}

//
//bool CTimerAndCTimerRoutine::DBTimerFire()
//{
//	if (m_pctimer_routine)
//	{
//		return m_pctimer_routine->DBTimerFire();
//	} 
//
//	return false;
//}
//
//
//
//bool CTimerAndCTimerRoutine::APPTimerFire()
//{
//	if (m_pctimer_routine)
//	{
//		return m_pctimer_routine->APPTimerFire();
//	} 
//
//	return false;
//}